from abc import ABC
from sqlite3 import connect, Connection
from typing import Optional

from api import CandidateList, Candidate, ImTranslator
from base import Dirs
from im_dict import ImDictLoader


class TableTranslator(ImTranslator):
    dictFile = ''
    dicts = {}

    def __init__(self, config) -> None:
        super().__init__()
        print('>>> create Translator')
        self.config = config
        self.dict = None
        self.pageSize = 9
        self.start = 0
        self.size = 0
        self.prevCode = ''
        self._applyConfig()

    def getPageSize(self) -> int:
        return self.pageSize

    def getStart(self) -> int:
        return self.start

    def getEnd(self) -> int:
        return self.start + self.size

    def translate(self, code: str, start: int = 0) -> CandidateList:
        self.prevCode = code
        result = CandidateList()
        if len(code) < 1:
            self.start = 0
            self.size = 0
            return result
        self.start = start
        print('>>> <{}> translate:`{}`, start={}'.format(__name__, code, start))
        items = self.dict.prefixMatch(code, start=start, limit=self.pageSize)
        for item in items:
            text = item.text
            result.append(Candidate(text=text, code=item.code, weight=item.weight))
        self.size = result.size()
        return result

    def pageUp(self) -> int:
        self.start = max(0, self.start - self.pageSize)
        return self.start

    def pageDown(self) -> int:
        if self.size >= self.pageSize:  # 还有下一页
            self.start += self.pageSize
        return self.start

    def _applyConfig(self):
        self.pageSize = self.config.get('pageSize')
        if self.dict is None:
            print('>>> start load dict.')
            f = self.config.get('dict')
            if f in TableTranslator.dicts:
                self.dict = self.dicts.get(f)
            else:
                ImDictLoader.dictFile = f
                self.dict = ImDictLoader().load(Dirs.fileInDataDir(f))
                TableTranslator.dicts[f] = self.dict
            print('>>> end load dict.')


class ScriptTranslator(ImTranslator):

    def __init__(self, config) -> None:
        super().__init__()
        self.config = config

    def getPageSize(self) -> int:
        pass

    def getStart(self) -> int:
        pass

    def getEnd(self) -> int:
        pass

    def translate(self, code: str, start: int = 0) -> CandidateList:
        pass

    def pageUp(self) -> int:
        pass

    def pageDown(self) -> int:
        pass


class SqliteTranslator(ImTranslator):
    conn: Optional[Connection] = None

    def __init__(self, config) -> None:
        super().__init__()
        self.config = config
        self.dict: Optional[str] = None
        self.pageSize = 9
        self.start = 0
        self.size = 0
        self.prevCode = ''
        self._applyConfig()
        self._connect()

    def getPageSize(self) -> int:
        return self.pageSize

    def getStart(self) -> int:
        return self.start

    def getEnd(self) -> int:
        return self.start + self.size - 1

    def translate(self, code: str, start: int = 0) -> CandidateList:
        result = CandidateList()
        if len(code) < 1:
            self.start = 0
            self.size = 0
            return result
        self.start = start
        sql = '''
        SELECT
            text_, code, weight
        from
            t_dict_gjwu
        where
            code like ?
        order by length(code), weight desc
        limit ?, ?
'''
        cursor = self.conn.execute(sql, [code + '%', start, self.pageSize])
        for row in cursor:
            result.append(Candidate(row[0], row[1], row[2]))
        self.size = result.size()
        cursor.close()
        return result

    def pageUp(self) -> int:
        self.start = max(0, self.start - self.pageSize)
        return self.start

    def pageDown(self) -> int:
        if self.size >= self.pageSize:  # 还有下一页
            self.start += self.pageSize
        return self.start

    def _applyConfig(self):
        self.pageSize = self.config.get('pageSize')
        if self.dict is None:
            self.dict = self.config.get('dict')

    def _connect(self):
        if SqliteTranslator.conn is None:
            SqliteTranslator.conn = connect(Dirs.fileInDataDir('ime.db'))


class Translators(ABC):
    @staticmethod
    def create(config) -> ImTranslator:
        type_ = config.get('type')
        if type_ == 'table':
            return TableTranslator(config)
        elif type_ == 'script':
            return ScriptTranslator(config)
        elif type_ == 'sqlite':
            return SqliteTranslator(config)
        raise Exception('Translators type: `{}` is not supported!'.format(type_))
